// clamloader.cpp : Defines the exported functions for the DLL application.
//

#include "clamloader.h"
#include <stdio.h>

//function prototype for libclamav.dll
typedef int (*CL_INIT)(unsigned int);
typedef struct cl_engine* (*CL_ENGINE_NEW)(void);
typedef int (*CL_ENGINE_FREE)(struct cl_engine *);
typedef const char* (*CL_RETVER)(void);
typedef int (*CL_LOAD)(const char *path, struct cl_engine *engine, unsigned int *signo, unsigned int dboptions);
typedef int (*CL_ENGINE_COMPILE)(struct cl_engine *engine);
typedef int (*CL_SCANFILE)(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
typedef const char* (*CL_STDERROR)(int clerror);
typedef struct cl_cvd* (*CL_CVDHEAD)(const char *file);

//global variable for clamav engine
HMODULE hClamAV = NULL;

struct cl_engine *engine = NULL;
unsigned int sigs = 0;

CL_INIT pcl_init = NULL;
CL_ENGINE_NEW pcl_engine_new = NULL;
CL_ENGINE_FREE pcl_engine_free = NULL;
CL_RETVER pcl_retver = NULL;
CL_LOAD pcl_load = NULL;
CL_ENGINE_COMPILE pcl_engine_compile = NULL;
CL_SCANFILE pcl_scanfile = NULL;
CL_STDERROR pcl_strerror;
CL_CVDHEAD pcl_cvdhead;


BOOL init_clamav()
{

	if (NULL == hClamAV)
	{
		///Load  clamav dll
		int ret = CL_SUCCESS;

		hClamAV = LoadLibrary("libclamav.dll");
		if (NULL == hClamAV)
		{
			printf("%\n", "Error loading libclamav.dll");
			return FALSE;
		}

		///Load specific function address
		pcl_init = (CL_INIT) GetProcAddress(hClamAV, "cl_init"); 
		pcl_engine_new = (CL_ENGINE_NEW) GetProcAddress(hClamAV, "cl_engine_new"); 
		pcl_engine_free = (CL_ENGINE_FREE) GetProcAddress(hClamAV, "cl_engine_free"); 
		pcl_engine_compile = (CL_ENGINE_COMPILE) GetProcAddress(hClamAV, "cl_engine_compile");
		pcl_retver = (CL_RETVER) GetProcAddress(hClamAV, "cl_retver"); 
		pcl_load = (CL_LOAD) GetProcAddress(hClamAV, "cl_load"); 
		pcl_scanfile = (CL_SCANFILE) GetProcAddress(hClamAV, "cl_scanfile");
		pcl_strerror = (CL_STDERROR) GetProcAddress(hClamAV, "cl_strerror");
		pcl_cvdhead = (CL_CVDHEAD) GetProcAddress(hClamAV, "cl_cvdhead");		

		if (NULL == pcl_init || 
			NULL == pcl_engine_new || 
			NULL == pcl_engine_free ||
			NULL == pcl_retver ||		
			NULL == pcl_engine_compile ||
			NULL == pcl_strerror ||
			NULL == pcl_cvdhead
			)
		{
			printf("%s\n", "Error loading clamav function address");
			return FALSE;
		}

		//initialize clamav engine

		ret= pcl_init(CL_INIT_DEFAULT);
		if (ret != CL_SUCCESS)
		{
			printf("Error calling cl_iinit(), return = %d\n", ret);
			return FALSE;
		}
		else
		{
			printf("cl_init() success\n");
		}

		engine = pcl_engine_new();

		if (NULL == engine)
		{
			printf("Error calling cl_engine_new()\n");
			return FALSE;
		}
		else
		{
			printf("New engine at %p\n", engine);
		}
	}
	else
	{
		printf("ClamAV already loaded!");
	}

	return TRUE;
}

BOOL load_signature(char *sig_file_name)
{
	struct cl_cvd *cvd_header;
	int ret = CL_SUCCESS;		
	FILE* fp = NULL;
	
	if(engine != NULL)
	{	

		cvd_header = pcl_cvdhead(sig_file_name);
		
		if (cvd_header != NULL)
		{
			printf("Load %s, ver=%d, time=%s, sig=%d\n", sig_file_name, cvd_header->version, cvd_header->time, cvd_header->sigs);	

			ret = pcl_load(sig_file_name, engine, &sigs, CL_DB_STDOPT);		

			if (CL_SUCCESS != ret)
			{
				printf("Error loading %s\n", sig_file_name);
				return FALSE;
			}

			printf("Total sig now %d\n", sigs);

			return TRUE;
		}
		

	}

	return FALSE;
}

BOOL compile_engine()
{
	int ret;

	if (engine != NULL)
	{
		ret = pcl_engine_compile(engine);	
		if (CL_SUCCESS == ret)
		{
			return TRUE;
		}
	}
	
	return FALSE;
	
}

const char *engine_ver()
{
	if((engine != NULL) && (pcl_retver != NULL))
	{
		return pcl_retver();
	}
	else
	{
		return NULL;
	}
}

const char *scan_file(char *file_name)
{
	int ret = CL_SUCCESS;
	const char *virus_name = NULL;

	if((ret = pcl_scanfile(file_name, &virus_name, NULL, engine,CL_SCAN_STDOPT)) == CL_VIRUS) 
	{
		return virus_name;
	}
	else 
	{		
		if(ret != CL_CLEAN)
		{
			printf("Scan error: %s\n", pcl_strerror(ret));
		}

		return NULL;
	}
}

BOOL cleanup_clamav()
{
	int ret = CL_SUCCESS;

	printf("Cleanup ClamAV\n");
	
	if(engine != NULL)
	{
		ret = pcl_engine_free(engine);
		if (ret != CL_SUCCESS)
		{
			printf("Error calling cl_engine_free()\n");
		}
		engine = NULL;
	}

	if (hClamAV != NULL)
	{
		FreeLibrary(hClamAV);
		hClamAV = NULL;
	}

	if(ret != CL_SUCCESS)
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}	
}
